﻿using SAO.OracleHelper.ValiDateModel;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace SAO.OracleHelper.MappingExtend
{
    /// <summary>
    /// 复制
    /// </summary>
    /// <typeparam name="TIn"></typeparam>
    /// <typeparam name="TOut"></typeparam>
    public class ExpressionGenericMapper<TIn, TOut>
    {
        private static Func<TIn, TOut> _FUNC = null;
        static ExpressionGenericMapper()
        {
            Type tIn = typeof(TIn);
            Type tOut = typeof(TOut);
            ParameterExpression parameterExpression = Expression.Parameter(tIn, "p");
            List<MemberBinding> memberBindingList = new List<MemberBinding>();
            foreach (PropertyInfo item in tOut.GetProperties())
            {
                if (!tIn.GetProperties().Select(s => s.Name).Contains(item.Name.DataBaseType(tOut))) continue;
                var prop = Expression.Property(parameterExpression, tIn.GetProperty(item.Name.DataBaseType(tOut)));
                MemberExpression property = prop;
                MemberBinding memberBinding = Expression.Bind(item, property);
                memberBindingList.Add(memberBinding);
            }
            foreach (FieldInfo item in tOut.GetFields())
            {
                if (!tIn.GetFields().Select(s => s.Name).Contains(item.Name.DataBaseType(tOut))) continue;
                MemberExpression property = Expression.Field(parameterExpression, tIn.GetField(item.Name.DataBaseType(tOut)));
                MemberBinding memberBinding = Expression.Bind(item, property);
                memberBindingList.Add(memberBinding);
            }
            MemberInitExpression memberInitExpression = Expression.MemberInit(Expression.New(tOut), memberBindingList.ToArray());
            Expression<Func<TIn, TOut>> lambda = Expression.Lambda<Func<TIn, TOut>>(memberInitExpression, new ParameterExpression[]
            {
                    parameterExpression
            });
            _FUNC = lambda.Compile();
        }
        public static TOut Trans(TIn t)
        {
            return _FUNC(t);
        }
        public static List<TOut> Trans(List<TIn> ins)
        {
            List<TOut> outs = new List<TOut>();
            foreach (TIn tin in ins)
            {
                outs.Add(Trans(tin));
            }
            return outs;
        }
        public static async Task<TOut> TransAsync(TIn @in)
        {
            Console.WriteLine($"{Thread.CurrentThread.ManagedThreadId}");
            var result = await Task.Factory.StartNew(() =>
            {
                return Trans(@in);
            });
            return result;
        }
        public static async Task<BlockingCollection<TOut>> TransAsync(List<TIn> ins)
        {
            BlockingCollection<TOut> outs = new BlockingCollection<TOut>();
            await Task.Factory.StartNew(() =>
            {
                foreach (TIn @in in ins)
                {
                    outs.Add(TransAsync(@in).Result);
                }
            });
            return outs;
        }
    }
}
